﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace Von.Library
{
    /// <summary>
    /// 关于图像处理的静态类
    /// </summary>
    public static class VonGraphic
    {
        public static string info = "";
        #region "ZOOM"
        /// <summary>
        /// 图形缩放类型
        /// </summary>
        public enum EImgZoomKind
        {
            /// <summary>
            /// 变形缩放，按指定列宽直接缩放
            /// </summary>
            IZK_FIX = 0,
            /// <summary>
            /// 固定宽缩放，从顶部截取
            /// </summary>
            IZK_FIX_W_T = 10,
            /// <summary>
            /// 固定宽缩放，中心截取
            /// </summary>
            IZK_FIX_W_C = 11,
            /// <summary>
            /// 固定宽缩放，从底部截取
            /// </summary>
            IZK_FIX_W_B = 12,
            /// <summary>
            /// 固定高缩放，从左边截取
            /// </summary>
            IZK_FIX_H_L = 20,
            /// <summary>
            /// 固定高缩放，中心截取
            /// </summary>
            IZK_FIX_H_C = 21,
            /// <summary>
            /// 固定高缩放，从右边截取
            /// </summary>
            IZK_FIX_H_R = 22,
            /// <summary>
            /// 自适应缩放，即以最短边为基础缩放，部分展示
            /// </summary>
            IZK_FIX_MAX = 30,
            /// <summary>
            /// 自适应缩放，即以最长边为基础缩放，全图展示
            /// </summary>
            IZK_FIX_FULL = 31,
            /// <summary>
            /// 智能缩放（是宽高比例，按比例的变化率决定用哪种方式展示）
            /// </summary>
            IZK_FIX_AUTO = 40,
        }
        /// <summary>
        /// 缩放图形文件
        /// </summary>
        /// <param name="orgFilename">原始图形文件</param>
        /// <param name="destFilename">目标图形文件</param>
        /// <param name="newWidth">目标宽</param>
        /// <param name="newHeight">目标高</param>
        public static void Zoom(string orgFilename, string destFilename, EImgZoomKind kind, int newWidth, int newHeight)
        {
            Image img = Image.FromFile(orgFilename);
            Image newImg = Zoom(img, kind, newWidth, newHeight);
            newImg.Save(destFilename, System.Drawing.Imaging.ImageFormat.Jpeg);
            newImg.Dispose();
        }
        /// <summary>
        /// 不变形放缩
        /// </summary>
        /// <param name="kind">图形缩放类型</param>
        /// <param name="orgImg">原始图</param>
        /// <param name="newWidth">目标宽</param>
        /// <param name="newHeight">目标高</param>
        /// <returns></returns>
        public static Image Zoom(Image orgImg, EImgZoomKind kind, int newWidth, int newHeight)
        {
            switch (kind)
            {
                case EImgZoomKind.IZK_FIX: return new Bitmap(orgImg, newWidth, newHeight);
                case EImgZoomKind.IZK_FIX_W_T:
                case EImgZoomKind.IZK_FIX_W_C:
                case EImgZoomKind.IZK_FIX_W_B:
                    return widthZoom(orgImg, kind, newWidth, newHeight);
                case EImgZoomKind.IZK_FIX_H_L:
                case EImgZoomKind.IZK_FIX_H_C:
                case EImgZoomKind.IZK_FIX_H_R:
                    return heightZoom(orgImg, kind, newWidth, newHeight);
                case EImgZoomKind.IZK_FIX_MAX:
                    if (newHeight - orgImg.Height > newWidth - orgImg.Width)
                        return heightZoom(orgImg, EImgZoomKind.IZK_FIX_H_C, newWidth, newHeight);
                    return widthZoom(orgImg, EImgZoomKind.IZK_FIX_W_C, newWidth, newHeight);
                case EImgZoomKind.IZK_FIX_FULL:
                    if (newHeight - orgImg.Height > newWidth - orgImg.Width)
                        return widthZoom(orgImg, EImgZoomKind.IZK_FIX_W_C, newWidth, newHeight);
                    return heightZoom(orgImg, EImgZoomKind.IZK_FIX_H_C, newWidth, newHeight);
                case EImgZoomKind.IZK_FIX_AUTO:
                    //double rateW = Convert.ToDouble(decimal.Divide(Math.Abs(newHeight - orgImg.Height), orgImg.Height));
                    //double rateH = Convert.ToDouble(decimal.Divide(Math.Abs(newWidth - orgImg.Width), orgImg.Width));
                    double rate = Convert.ToDouble(decimal.Divide(newHeight * orgImg.Width, orgImg.Height * newWidth));
                    //if ((rate > 1 && newHeight > orgImg.Height) || (rate < 1 && newHeight < orgImg.Height))
                    //高度变化比较大的放大，以高为主的截取，宽度变化比较大缩小，以高度为主
                    //    if (Math.Abs(newHeight - orgImg.Height) > Math.Abs(newWidth - orgImg.Width))
                    if (rate > 1.5 || rate < 0.666)
                    {
                        if (orgImg.Height > orgImg.Width) return widthZoom(orgImg, EImgZoomKind.IZK_FIX_W_C, newWidth, newHeight);
                        else return heightZoom(orgImg, EImgZoomKind.IZK_FIX_H_C, newWidth, newHeight);
                    }
                    if (orgImg.Height > orgImg.Width)
                        return heightZoom(orgImg, EImgZoomKind.IZK_FIX_H_C, newWidth, newHeight);
                    return widthZoom(orgImg, EImgZoomKind.IZK_FIX_W_C, newWidth, newHeight);
            }
            return null;
        }
        /// <summary>
        /// 定宽截取
        /// </summary>
        /// <param name="orgImg">原始图片</param>
        /// <param name="kind">定宽类型</param>
        /// <param name="newWidth">新宽度</param>
        /// <param name="newHeight">新高度</param>
        /// <returns></returns>
        private static Image widthZoom(Image orgImg, EImgZoomKind kind, int newWidth, int newHeight)
        {
            int szHeight = orgImg.Height * newWidth / orgImg.Width;
            Bitmap szBmp = new Bitmap(orgImg, newWidth, szHeight);
            Bitmap result = new Bitmap(newWidth, newHeight);
            Rectangle orgRect;
            int szInt = szHeight > newHeight ? 0 : (newHeight - szHeight) / 2;
            Rectangle destRect = new Rectangle(0, szInt, newWidth, newHeight - szInt);
            switch (kind)
            {
                case EImgZoomKind.IZK_FIX_W_T:
                    szInt = 0;
                    break;
                case EImgZoomKind.IZK_FIX_W_C:
                    szInt = szHeight > newHeight ? (szHeight - newHeight) / 2 : 0;
                    break;
                default:
                    szInt = szHeight > newHeight ? szHeight - newHeight : 0;
                    break;
            }
            orgRect = new Rectangle(0, szInt, newWidth, destRect.Height);
            Graphics g = Graphics.FromImage(result);
            g.DrawImage(szBmp, destRect, orgRect, GraphicsUnit.Pixel);
            return result;
        }
        /// <summary>
        /// 定高截取
        /// </summary>
        /// <param name="orgImg">原始图片</param>
        /// <param name="kind">定高类型</param>
        /// <param name="newWidth">新宽度</param>
        /// <param name="newHeight">新高度</param>
        /// <returns></returns>
        private static Image heightZoom(Image orgImg, EImgZoomKind kind, int newWidth, int newHeight)
        {
            int szWidth = (int)(1.00000 * orgImg.Width * newHeight / orgImg.Height);
            Bitmap szBmp = new Bitmap(orgImg, szWidth, newHeight);
            Bitmap result = new Bitmap(newWidth, newHeight);
            Rectangle orgRect;
            int szInt = szWidth > newWidth ? 0 : (newWidth - szWidth) / 2;
            Rectangle destRect = new Rectangle(szInt, 0, newWidth - szInt, newHeight);
            switch (kind)
            {
                case EImgZoomKind.IZK_FIX_H_L:
                    szInt = 0;
                    break;
                case EImgZoomKind.IZK_FIX_H_C:
                    szInt = szWidth > newWidth ? (szWidth - newWidth) / 2 : 0;
                    break;
                default:
                    szInt = szWidth > newWidth ? szWidth - newWidth : 0;
                    break;
            }
            orgRect = new Rectangle(szInt, 0, destRect.Width, newHeight);
            Graphics g = Graphics.FromImage(result);
            g.DrawImage(szBmp, destRect, orgRect, GraphicsUnit.Pixel);
            return result;
        }
        #endregion
        #region "Rotation"
        /// <summary>
        /// 
        /// </summary>
        /// <param name="img">图像</param>
        /// <param name="angle">旋转角度</param>
        /// <param name="hFlip">水平翻转</param>
        /// <param name="vFlip">垂直翻转</param>
        /// <returns></returns>
        public static Image Rotation(Image img, float angle, bool hFlip, bool vFlip)
        {
            RotateFlipType[,] arrRTF = new RotateFlipType[,] { 
                //          不进行翻转的                  水平翻转                        垂直翻转                     水平翻转和垂直翻转   
                { RotateFlipType.RotateNoneFlipNone, RotateFlipType.RotateNoneFlipX, RotateFlipType.RotateNoneFlipY, RotateFlipType.RotateNoneFlipXY },   // 0 度旋转
                { RotateFlipType.Rotate90FlipNone, RotateFlipType.Rotate90FlipX, RotateFlipType.Rotate90FlipY, RotateFlipType.Rotate90FlipXY },     //90 度旋转
                { RotateFlipType.Rotate180FlipNone, RotateFlipType.Rotate180FlipX, RotateFlipType.Rotate180FlipY, RotateFlipType.Rotate180FlipXY }, //180度旋转
                { RotateFlipType.Rotate270FlipNone, RotateFlipType.Rotate270FlipX, RotateFlipType.Rotate270FlipY, RotateFlipType.Rotate270FlipXY }};//270度旋转
            int dimAngle = -1;
            if (angle == 0) dimAngle = 0;
            else if (angle == 90) dimAngle = 1;
            else if (angle == 180) dimAngle = 2;
            else if (angle == 270) dimAngle = 3;
            if (dimAngle >= 0)
            {
                img.RotateFlip(arrRTF[dimAngle, (hFlip ? 1 : 0) + (vFlip ? 2 : 0)]);
                return img;
            }
            else
            {
                int w = img.Width + 2;
                int h = img.Height + 2;
                PixelFormat pf = PixelFormat.Format32bppArgb;
                Bitmap tmp = new Bitmap(w, h, pf);
                Graphics g = Graphics.FromImage(tmp);
                g.Clear(Color.Transparent);
                g.DrawImageUnscaled(img, 1, 1);
                g.Dispose();

                GraphicsPath path = new GraphicsPath();
                path.AddRectangle(new RectangleF(0f, 0f, w, h));
                Matrix mtrx = new Matrix();
                mtrx.Rotate(angle);
                RectangleF rct = path.GetBounds(mtrx);

                Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);
                g = Graphics.FromImage(dst);
                g.Clear(Color.Transparent);
                g.TranslateTransform(-rct.X, -rct.Y);
                g.RotateTransform(angle);
                g.InterpolationMode = InterpolationMode.HighQualityBilinear;
                g.DrawImageUnscaled(tmp, 0, 0);
                g.Dispose();
                tmp.Dispose();
                return dst;
            }
        }
        #endregion
        #region "Color change"
        /// <summary>
        /// 灰度化一个图片
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static Image Gray(Image img)
        {
            Bitmap result = img.Clone() as Bitmap;
            Rectangle rect = new Rectangle(0, 0, result.Width, result.Height);
            BitmapData bmpdata = result.LockBits(rect, ImageLockMode.ReadWrite, result.PixelFormat);
            byte temp;

            unsafe
            {
                byte* ptr = (byte*)(bmpdata.Scan0);

                for (int x = 0; x < bmpdata.Width; x++)
                {
                    for (int y = 0; y < bmpdata.Height; y++)
                    {
                        temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                        ptr[0] = ptr[1] = ptr[2] = temp;
                        ptr += 3;
                    }
                    ptr += bmpdata.Stride - bmpdata.Width * 3;
                }
            }
            result.UnlockBits(bmpdata);
            return result as Image;
        }
        /// <summary>
        /// 本函数完成的功能是图像颜色的翻转，实现的方法即用255减去图像中的每个象素点的值，并将所得值设置为原象素点处的值，对每个象素点进行如此的操作，只到整幅图像都处理完毕。
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns>函数执行成功，最后返回true值</returns>
        public static Image Invert(Image img)
        {
            Bitmap bmp = new Bitmap(img);
            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                int nOffset = stride - bmp.Width * 3;
                int nWidth = bmp.Width * 3;
                for (int y = 0; y < bmp.Height; ++y)
                {
                    for (int x = 0; x < nWidth; ++x)
                    {
                        p[0] = (byte)(255 - p[0]);
                        ++p;
                    }
                    p += nOffset;
                }
            }
            bmp.UnlockBits(bmData);
            return bmp;
        }
        /// <summary>
        /// 本函数完成的功能是对图像进行增亮处理。在取得了增亮参数后，函数的unsafe代码部分对每个象素点的不同颜色成分进行逐个处理，即在原来值的基础上加上一个增亮参数以获得新的值。同时代码中还有一个防止成分值越界的操作，因为RGB成分值的范围为0～255，一旦超过了这个范围就要重新设置。
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="nBrightness">增亮参数，范围为－255～255</param>
        /// <returns>函数最后执行成功后，同样得返回true值。</returns>
        public static Image Brightness(Image img, int nBrightness)
        {
            Bitmap bmp = new Bitmap(img);
            if (nBrightness < -255 || nBrightness > 255) return img;
            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            int nVal = 0;
            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                int nOffset = stride - bmp.Width * 3;
                int nWidth = bmp.Width * 3;
                for (int y = 0; y < bmp.Height; ++y)
                {
                    for (int x = 0; x < nWidth; ++x)
                    {
                        nVal = (int)(p[0] + nBrightness);
                        if (nVal < 0) nVal = 0;
                        if (nVal > 255) nVal = 255;
                        p[0] = (byte)nVal;
                        ++p;
                    }
                    p += nOffset;
                }
            }
            bmp.UnlockBits(bmData);
            return bmp;
        }
        /// <summary>
        /// 以浮雕效果显示图像
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static Image Anaglyph(Image img)
        {
            Bitmap newBitmap = new Bitmap(img);
            Bitmap oldBitmap = (Bitmap)img;
            Color pixel1, pixel2;
            for (int x = 0; x < img.Width - 1; x++)
            {
                for (int y = 0; y < img.Height - 1; y++)
                {
                    int r = 0, g = 0, b = 0;
                    pixel1 = oldBitmap.GetPixel(x, y);
                    pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
                    r = Math.Abs(pixel1.R - pixel2.R + 128);
                    g = Math.Abs(pixel1.G - pixel2.G + 128);
                    b = Math.Abs(pixel1.B - pixel2.B + 128);
                    if (r > 255)
                        r = 255;
                    if (r < 0)
                        r = 0;
                    if (g > 255)
                        g = 255;
                    if (g < 0)
                        g = 0;
                    if (b > 255)
                        b = 255;
                    if (b < 0)
                        b = 0;
                    newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
                }
            }
            return newBitmap;
        }
        /// <summary>
        /// 以柔化效果显示图像
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static Image Soften(Image img)
        {
            Bitmap bitmap = new Bitmap(img);
            Bitmap MyBitmap = (Bitmap)img;
            Color pixel;
            //高斯模板
            int[] Gauss = { 1, 2, 1, 2, 4, 2, 1, 2, 1 };
            for (int x = 1; x < img.Width - 1; x++)
                for (int y = 1; y < img.Height - 1; y++)
                {
                    int r = 0, g = 0, b = 0;
                    int Index = 0;
                    for (int col = -1; col <= 1; col++)
                        for (int row = -1; row <= 1; row++)
                        {
                            pixel = MyBitmap.GetPixel(x + row, y + col);
                            r += pixel.R * Gauss[Index];
                            g += pixel.G * Gauss[Index];
                            b += pixel.B * Gauss[Index];
                            Index++;
                        }
                    r /= 16;
                    g /= 16;
                    b /= 16;
                    //处理颜色值溢出
                    r = r > 255 ? 255 : r;
                    r = r < 0 ? 0 : r;
                    g = g > 255 ? 255 : g;
                    g = g < 0 ? 0 : g;
                    b = b > 255 ? 255 : b;
                    b = b < 0 ? 0 : b;
                    bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
                }
            return bitmap;
        }
        /// <summary>
        /// 以锐化效果显示图像
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static Image Sharpen(Image img)
        {
            Bitmap newBitmap = new Bitmap(img);
            Bitmap oldBitmap = (Bitmap)img;
            Color pixel;
            //拉普拉斯模板
            int[] Laplacian = { -1, -1, -1, -1, 9, -1, -1, -1, -1 };
            for (int x = 1; x < img.Width - 1; x++)
                for (int y = 1; y < img.Height - 1; y++)
                {
                    int r = 0, g = 0, b = 0;
                    int Index = 0;
                    for (int col = -1; col <= 1; col++)
                        for (int row = -1; row <= 1; row++)
                        {
                            pixel = oldBitmap.GetPixel(x + row, y + col); r += pixel.R * Laplacian[Index];
                            g += pixel.G * Laplacian[Index];
                            b += pixel.B * Laplacian[Index];
                            Index++;
                        }
                    //处理颜色值溢出
                    r = r > 255 ? 255 : r;
                    r = r < 0 ? 0 : r;
                    g = g > 255 ? 255 : g;
                    g = g < 0 ? 0 : g;
                    b = b > 255 ? 255 : b;
                    b = b < 0 ? 0 : b;
                    newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
                }
            return newBitmap;
        }
        #endregion
        #region "水印处理"
        /// <summary>
        /// 添加文字行水印，位置在1/3处，横向铺满
        /// </summary>
        /// <param name="img">图像</param>
        /// <param name="watermarkText">水印文字</param>
        /// <param name="fontName">水印字体，为null或空时默认为“宋体”</param>
        /// <param name="fontSize">水印字体大小，小于零时，默认大小为50</param>
        /// <returns></returns>
        public static Image WaterMark(Image img, string watermarkText, string fontName, int fontSize)
        {
            Bitmap bmp = new Bitmap(img);
            using (System.Drawing.Graphics gWater = System.Drawing.Graphics.FromImage(bmp))
            {
                if (fontName == null || fontName == "") fontName = "宋体";
                if (fontSize < 1) fontSize = 50;
                System.Drawing.Font fontWater = new Font(fontName, 50);
                System.Drawing.Brush brushWater = new SolidBrush(Color.FromArgb(50, Color.Gray));
                string waterStr = watermarkText + "  ";
                SizeF sz = gWater.MeasureString(waterStr, fontWater);
                for (int i = 0; i < img.Width / sz.Width; i++)
                    waterStr += watermarkText + "  ";
                gWater.DrawString(waterStr, fontWater, brushWater, 0, img.Height/3);
                gWater.Dispose();
            }
            return bmp;
        }
        /// <summary>
        /// 添加图像水印，中间区域横向铺满
        /// </summary>
        /// <param name="img">原图像</param>
        /// <param name="waterImage">水印图像</param>
        /// <returns></returns>
        public static Image WaterMark(Image img, Image waterImage)
        {
            Bitmap bmp = new Bitmap(img);
            Graphics gWater = Graphics.FromImage(bmp);
            //透明属性
            ImageAttributes imgAttributes = new ImageAttributes();
            ColorMap colorMap = new ColorMap();
            colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
            colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
            ColorMap[] remapTable = { colorMap };
            imgAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
            float[][] colorMatrixElements = {
                new float[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                new float[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                new float[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                new float[] {0.0f,  0.0f,  0.0f,  0.3f, 0.0f},//透明度:0.5
                new float[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f} };
            ColorMatrix wmColorMatrix = new ColorMatrix(colorMatrixElements);
            imgAttributes.SetColorMatrix(wmColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            int xOffset = 0;
            do
            {
                gWater.DrawImage(waterImage, new Rectangle(xOffset, (bmp.Height - waterImage.Height)/2, waterImage.Width, waterImage.Height), 0, 0, waterImage.Width, waterImage.Height, GraphicsUnit.Pixel, imgAttributes);
                xOffset += waterImage.Width;
            } while (bmp.Width > xOffset);
            gWater.Dispose();
            return bmp;
        }
        #endregion
        public static void ConvertImgStream(Stream inStream, Stream outStream, ImageFormat fmt)
        {
            Image image = Bitmap.FromStream(inStream);
            if (fmt.Equals(ImageFormat.Icon))
            {
                using (var bin = new BinaryWriter(outStream))
                {
                    MemoryStream msImg = new MemoryStream();
                    inStream.Position = 0;
                    image.Save(msImg, ImageFormat.Png);
                    //写图标头部
                    bin.Write((short)0);           //0-1保留
                    bin.Write((short)1);           //2-3文件类型。1=图标, 2=光标
                    bin.Write((short)1);           //4-5图像数量（图标可以包含多个图像）

                    bin.Write((byte)image.Width);  //6图标宽度
                    bin.Write((byte)image.Height); //7图标高度
                    bin.Write((byte)0);            //8颜色数（若像素位深>=8，填0。这是显然的，达到8bpp的颜色数最少是256，byte不够表示）
                    bin.Write((byte)0);            //9保留。必须为0
                    bin.Write((short)0);           //10-11调色板
                    bin.Write((short)32);          //12-13位深
                    bin.Write((int)inStream.Length);  //14-17位图数据大小
                    bin.Write(22);                 //18-21位图数据起始字节
                                                   //写图像数据
                    bin.Write(msImg.ToArray());

                    bin.Flush();
                    bin.Seek(0, SeekOrigin.Begin);
                }
                //Bitmap bmp = new Bitmap(image);
                //bmp.MakeTransparent(Color.White);
                //System.IntPtr icH = bmp.GetHicon();
                //Icon ico = Icon.FromHandle(icH);
                //bmp.Dispose();
                //ico.Save(outStream);
                //ico.Dispose();


                //IntPtr h = bmp.GetHicon();
                //System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(h);
                //icon.Save(outStream);
                ////Marshal.FreeHGlobal(h);// 释放百度IntPtr
                //icon.Dispose();
            }
            else
            {
                inStream.Position = 0;
                image.Save(outStream, fmt);
            }
        }
    }
}
